import java.util.Properties;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;

import com.sun.mail.pop3.POP3SSLStore;

/* Test POP3 Connectivity for following ports: 
 * 		port 110 : normal POP3 (through aol)
 * 		port 995 : POP3S (through gmail)
 * 
 *	Usage for this class is as follows: 
 * 		1) Create new class
 * 		2) Call setProperties(int port)
 * 		3) call runtests (int numberOfTests)
 */
public class AllPOP3Connectivity implements Runnable {
	
	ConnectionStatus internetStatus = new ConnectionStatus();
	
	private String HOST_NAME;
	private int HOST_PORT;
	private String AUTH_USER;
	private String AUTH_PWD;
	private String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
	
	private Properties props = new Properties();
	URLName url;
	
	private boolean badFlag = true; // used for the case that the user provides a bad port
	

	// for thread synchronization
	ResultsTable sharedTable = new ResultsTable();
	private int numTests;
	static CyclicBarrier barrier;
	String POP_KEY;
	
	
	public AllPOP3Connectivity(ResultsTable r, CyclicBarrier b, int n) {
		sharedTable = r;
		barrier = b;
		numTests = n;
	}
	
	
	@Override
	public void run() {
		try {
			internetStatus = runTests(numTests);
		} catch (Exception e) {
		}
			sharedTable.addResult(POP_KEY, internetStatus); // add result to table
		
		try {
			barrier.await();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
		
		
	}

	public void setProperties(int port) {
		if (port == 110) {
			POP_KEY = "pop";
			badFlag = false;
//			HOST_NAME = "pop1.mail.com";
//			AUTH_USER = "mifcais@mail.com";
//			HOST_NAME = "pop.mail.lycos.com";
//			AUTH_USER = "mifcais@lycos.com";
			HOST_NAME = "pop.aol.com";
			AUTH_USER = "mifcais@aol.com";
			HOST_PORT = 110;
			AUTH_PWD = "COMSE6181";			
			props = System.getProperties();		
		    props.put("mail.pop3.host", HOST_NAME);
		    props.put("mail.pop3.port", "110");
		    props.put("mail.pop3.auth", "true");
			props.put("mail.store.protocol", "pop3");						
						
		} else if (port == 995) {
			POP_KEY = "pops";
			badFlag = false;
			HOST_NAME = "pop.gmail.com";
			HOST_PORT = 995;
			AUTH_USER = "mifcais2@gmail.com";
			AUTH_PWD = "COMSE6181";			
			props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
			props.setProperty("mail.pop3.ssl.enable", "true");
			props.setProperty("mail.pop3.socketFactory.fallback", "false");
            props.setProperty("mail.pop3.port", "995");
            props.setProperty("mail.pop3.socketFactory.port", "995");									        
	        url = new URLName("pop3", HOST_NAME, HOST_PORT, "", AUTH_USER, AUTH_PWD);
	        
		} else {
			System.out.println("You have provided a bad port");
			badFlag = true;
		}
	}
				
	public ConnectionStatus runTests (int n){
		System.out.println("In POP3 RUN for port " + HOST_PORT);
		
			for (int i = 0; i < n; i++){
				// run the test n times
				if (isConnected() && !badFlag) {
					this.internetStatus.addPassedAttempt();
				} else {
					this.internetStatus.addFailedAttempt();
				}
			}			
			
		return this.internetStatus;
	}
	
    private boolean isConnected(){
    	
    	boolean result = false; // initialize result as false
    	
    	if (! (HOST_PORT == 110 || HOST_PORT == 995) )
    		return result;
    	
    	if (HOST_PORT == 995) {
	        Session mailSession = Session.getInstance(props, null);
	        mailSession.setDebug(false);
	        Store store = new POP3SSLStore(mailSession, url);
	        try {
				store.connect();
				 store.close();
			} catch (MessagingException e) {
				return false;
			}
	        /* This is where the commands that actually fetch the messages would go. Again, 
	         * we only need to connect so they are omitted */
	           	 	        
	        result = true; // if we reached that point ==> everything went ok.
    	} else { 	// HOST_PORT == 110
    		Session mailSession = Session.getDefaultInstance(props, null);
    		Store store;
			try {
				store = mailSession.getStore("pop3");
				if (!store.isConnected())
	    			store.connect(HOST_NAME, AUTH_USER, AUTH_PWD);
	    		else
	    			System.out.println("Is already connected");
	    			store.close();
	    		result = true;   
			} catch (NoSuchProviderException e) {
				return false;
			} catch (MessagingException e) {
				return false;
			}
    		 		
    	}
        return result;
    }
}